package com.github.glomadrian.roadrunner.painter.indeterminate;

import com.github.glomadrian.roadrunner.painter.RoadRunnerPainter;
import com.github.glomadrian.roadrunner.painter.configuration.Direction;
import com.github.glomadrian.roadrunner.painter.configuration.indeterminate.TwoWayIndeterminateConfiguration;
import com.github.glomadrian.roadrunner.path.PathContainer;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;

/**
 * @author Adrián García Lomas
 */
public class TwoWayIndeterminatePainter extends RoadRunnerPainter
    implements IndeterminatePathPainter {

  private AnimatorValue movementAnimator;
  private AnimatorValue leftLineAnimator;
  private AnimatorValue rightLineAnimator;
  private int offsetRight = 0;
  private int offsetLeft = 0;
  private int movementLoopTime = 5000;
  private float movementLineSize = 0.005f;

  //Right line configuration
  private int rightLineLoopTime = 5000;
  private int rightLineStartDelayTime = 2000;
  private float rightLineMaxSize = 0.5f;
  //Left line configuration
  private int leftLineLoopTime = 2000;
  private int leftLineStartDelayTime = 5000;
  private float leftLineMaxSize = 0.5f;
  private int leftPoints;
  private int rightPoints;
  private int leftType;
  private int rightType;

  /**
   * TwoWayIndeterminatePainter
   *
   * @param view
   * @param pathContainer
   * @param twoWayIndeterminateConfiguration
   */
  public TwoWayIndeterminatePainter(Component view, PathContainer pathContainer,
                                    TwoWayIndeterminateConfiguration twoWayIndeterminateConfiguration) {
    super(pathContainer, view);
    initConfiguration(twoWayIndeterminateConfiguration);
    init();
  }

  private void initConfiguration(
      TwoWayIndeterminateConfiguration twoWayIndeterminateConfiguration) {
    movementDirection = twoWayIndeterminateConfiguration.getMovementDirection();
    color = twoWayIndeterminateConfiguration.getColor();
    strokeWidth = twoWayIndeterminateConfiguration.getStrokeWidth();
    movementLoopTime = twoWayIndeterminateConfiguration.getMovementLoopTime();
    rightLineLoopTime = twoWayIndeterminateConfiguration.getRightLineLoopTime();
    movementLineSize = twoWayIndeterminateConfiguration.getMovementLineSize();
    rightLineStartDelayTime = twoWayIndeterminateConfiguration.getRightLineStartDelayTime();
    rightLineMaxSize = twoWayIndeterminateConfiguration.getRightLineMaxSize();
    leftLineLoopTime = twoWayIndeterminateConfiguration.getLeftLineLoopTime();
    leftLineStartDelayTime = twoWayIndeterminateConfiguration.getLeftLineStartDelayTime();
    leftLineMaxSize = twoWayIndeterminateConfiguration.getLeftLineMaxSize();
  }

  private void init() {
    initPaint();
    initLineMovement();
    initMovementAnimator();
    initRightLineAnimator();
    initLeftLineAnimator();
  }

  private void initLineMovement() {
    movementLinePoints = getNumberOfLinePointsInRange(movementLineSize);
  }

  private void initMovementAnimator() {
    movementAnimator = new AnimatorValue();
    movementAnimator.setDuration(movementLoopTime);
    movementAnimator.setCurveType(Animator.CurveType.SMOOTH_STEP);
    movementAnimator.setLoopedCount(AnimatorValue.INFINITE);
    movementAnimator.setValueUpdateListener(new MovementLineAnimatorUpdateListener());
  }

  private void initRightLineAnimator() {
    rightPoints = getPositionForZone(rightLineMaxSize);
    rightLineAnimator = new AnimatorValue();
    rightType = 1;
    rightLineAnimator.setDuration(rightLineLoopTime);
    rightLineAnimator.setLoopedCount(AnimatorValue.INFINITE);
    rightLineAnimator.setDelay(rightLineStartDelayTime);
    rightLineAnimator.setValueUpdateListener(new RightLineAnimatorUpdateListener());
    rightLineAnimator.setLoopedListener(animator -> rightType = rightType == 1 ? 2 : 1);
  }

  private void initLeftLineAnimator() {
    leftType = 1;
    leftPoints = getPositionForZone(leftLineMaxSize);
    leftLineAnimator = new AnimatorValue();
    leftLineAnimator.setDuration(leftLineLoopTime);
    leftLineAnimator.setLoopedCount(AnimatorValue.INFINITE);
    leftLineAnimator.setDelay(leftLineStartDelayTime);
    leftLineAnimator.setValueUpdateListener(new LeftLineAnimatorUpdateListener());
    leftLineAnimator.setLoopedListener(animator -> leftType = leftType == 1 ? 2 : 1);
  }

  /**
   * initPaint
   */
  public void initPaint() {
    paint = new Paint();
    paint.setColor(new Color(color));
    paint.setStrokeWidth(strokeWidth);
  }

  @Override
  public void paintPath(Canvas canvas) {
    drawWithOffset(zone, offsetRight, offsetLeft, movementLinePoints, canvas, paint);
  }

  @Override
  public void start() {
    movementAnimator.start();
    leftLineAnimator.start();
    rightLineAnimator.start();
  }

  @Override
  public void stop() {
    movementAnimator.cancel();
    leftLineAnimator.cancel();
    rightLineAnimator.cancel();
  }

  @Override
  public void restart() {
    stop();
    start();
  }

  private class MovementLineAnimatorUpdateListener implements AnimatorValue.ValueUpdateListener {
    @Override
    public void onUpdate(AnimatorValue animatorValue, float v) {
      if (movementDirection.equals(Direction.CLOCKWISE)) {
        zone = v;
      } else {
        zone = 1 - v;
      }
      view.invalidate();
    }
  }

  private class RightLineAnimatorUpdateListener implements AnimatorValue.ValueUpdateListener {
    @Override
    public void onUpdate(AnimatorValue animatorValue, float v) {
      if (rightType == 1){
        offsetRight = (int) (v * rightPoints);
      } else {
        offsetRight = (int) ( (1 - v) * rightPoints);
      }
//      if (v > 0.98 && v<= 1.0){
//        if (movementDirection.equals(Direction.CLOCKWISE)) {
//          movementDirection = Direction.COUNTER_CLOCKWISE;
//        }else {
//          movementDirection = Direction.CLOCKWISE;
//        }
//      }
    }
  }

  private class LeftLineAnimatorUpdateListener implements AnimatorValue.ValueUpdateListener {
    @Override
    public void onUpdate(AnimatorValue animatorValue, float v) {

      if (leftType == 1){
         offsetLeft = (int) (v * leftPoints);
      } else {
         offsetLeft = (int) ( (1 - v) * leftPoints);
      }
      System.out.println("------ leftType = " + leftType);
    }
  }
}
